import { ReactiveEffect } from "./effect";
import type { fn } from "./index.d";
//计算属性的实现很巧妙，缓存是通过 _dirty 作为一个锁来实现的，只有为true才会重新执行，并把_dirty设置为false。
//但是什么时候会让 _dirty = true 呢，这里使用了effect，让getter中的响应式变量发生改变时，执行 scheduler，把_dirty设置为true
//因为如果getter中有响应式数据，那么必定会涉及到响应式的get操作，就会触发依赖收集，这样当响应式被set时，就会触发这个依赖，把_dirty设置为true
//这样下次get操作的时候，就会给出最新的值了

/**计算属性的类 */
class ComputedRefImpl<T>{
    /**计算属性的getter函数 */
    private _getter: fn<T>
    /**是否需要更新数据。用于缓存机制。当getter中响应式的值发生改变了，才会变为true */
    private _dirty: boolean = true
    /**当前computed对应的effect。用于及时更新 */
    private _effect: ReactiveEffect
    /**缓存的值 */
    private _value!: T;

    /**构造函数
     * @param getter getter函数，在这里的返回值会作为计算属性的最终值
     */
    constructor(getter: fn<T>) {
        this._getter = getter
        //使用 effect 来实现 “当getter中响应式的值发生改变了，才会变为true”。因为如果getter中有响应式数据，那么必定会涉及到get操作，这时候就会把下面这个依赖给收集进去了，特别巧妙，这样当响应式被set时，就会触发这个依赖，把_dirty设置为true
        this._effect = new ReactiveEffect(getter, () => {//设置scheduler，这个函数是在每次 ReactiveEffect 实例 run 的时候，会优先执行这个，而不执行第一个参数
            this._dirty = true //设置为需要更新
        })
    }

    /**计算属性的值 */
    get value() {
        if (this._dirty) {//如果需要更新，就执行一次函数
            this._dirty = false //设置为不需要更新
            this._value = this._effect.run()
        }
        return this._value
    }
}



/**计算属性
 * @param getter getter函数，在这里的返回值会作为计算属性的最终值
 */
export function computed<T = any>(getter: fn<T>): ComputedRefImpl<T> {
    return new ComputedRefImpl(getter)
}